#!/usr/bin/python
# -*- coding:utf-8 -*-

import logging
import socket
import struct
import mcpack
import random

class NsheadTsheadMcpack:

    def __init__(self):
        pass

    def get_ns_head(self):
        return {
            "id": 0,
            "version": 1,
            "log_id": random.randint(100000, 999999),
            "provider": "python_send",
            "magic_num": 0xfb709394,
            "reserved": 0,
            "body_len": 0,
        }

    def makeNsHead(self, ns_head, length):
        if ns_head is None:
            ns_head = self.getNsHead()
        ns_head["body_len"] = length

        header = []
        for i in ["id", "version", "log_id", "provider", "magic_num", "reserved", "body_len"]:
            header.append(ns_head[i])
        # format of header: 2*unsigned short + uint + string with size=16 + 3*uint = 36 byte
        header_p = struct.pack("2HI16s3I", *header)
        return header_p

    def get_ts_head(self):
        return {"cmd_no": 100003,           #UINT32
                "err_no": 0,                #UINT32
                "data_type": "updatetime",  #char[64]
                "page_no": 0,               #UINT32
                "num_per_page": 20,         #UINT32
                "ret_num": 0,               #UINT32
                "disp_num": 0,              #UINT32
                }

    def makeTsHead(self, ts_head):
        if ts_head is None:
            ts_head = self.get_ts_head()
        header = []
        for i in ['cmd_no', 'err_no', 'data_type', 'page_no', 'num_per_page', 'ret_num', 'disp_num']:
            header.append(ts_head[i])
        # format of header: 2*uint32 + 64*char + 4*uint32 = 8+64+16=88 byte
        header_p = struct.pack("2I64s4I", *header)
        return header_p

    def parseNsHead(self, header):
        return struct.unpack("2HI16s3I", header)

    def parseTsHead(self, header):
        return struct.unpack("2I64s4I", header)

    def recvMcpack(self, sk, total):
        data = ""
        length = total
        while length > 0:
            data += sk.recv(length)
            length = total - len(data)
        return data

    def recv_nsmc(self, sk):
        try:
            nshead_data = sk.recv(36)
            nshead_header = self.parseNsHead(nshead_data)
        except:
            logging.error("recv header failed!")
            return False

        other_data = self.recvMcpack(sk, nshead_header[-1])

        res_dict = {}
        res_dict['nshead'] = nshead_header
        res_dict['mcpack'] = mcpack.loads(other_data)
        return res_dict

    def recv_nstsmc(self, sk):
        try:
            nshead_data = sk.recv(36)
            nshead_header = self.parseNsHead(nshead_data)
        except:
            logging.error("recv header failed!")
            return False

        other_data = self.recvMcpack(sk, nshead_header[-1])
        tshead_header = other_data[0:88]
        mcpack_data = other_data[88:]

        res_dict = {}
        res_dict['nshead'] = nshead_header
        res_dict['tshead'] = self.parseTsHead(tshead_header)
        res_dict['mcpack'] = mcpack.loads(mcpack_data)
        return res_dict

    def send_nstsmc(self, addr, nshead, tshead, data):
        res_dict = {}
        sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sk.settimeout(5)
        try:
            sk.connect(addr)
        except Exception, e:
            logging.error("Cannot connect to EC@%s", addr)
            logging.error(e)
            res_dict['error'] = str(e)
            return res_dict

        pack = mcpack.dumps_version(mcpack.mcpackv1, data, buffer_size=2*1024*1024)
        
        try:
            if tshead != None:
                tshead_header = self.makeTsHead(tshead)
                nshead_header = self.makeNsHead(nshead, len(tshead_header + pack))
                sk.sendall(nshead_header + tshead_header + pack)
                res_dict = self.recv_nstsmc(sk)
            else:
                nshead_header = self.makeNsHead(nshead, len(pack))
                sk.sendall(nshead_header + pack)
                res_dict = self.recv_nsmc(sk)
        except Exception, e:
            logging.error(e)

        sk.close()
        return res_dict
